/*
 * To change this template, choose JavaTool | Templates
 * and open the template in the editor.
 */
package yinshi.fsm;

import java.io.IOException;
import yinshi.util.Graph;
import yinshi.util.Graph.Link;
import yinshi.util.Graph.Node;
import yinshi.util.JavaTool;

/**
 *
 * @author yinshi
 
public class TextParser2 {

    private Object entryKey;
    private final Graph graph = new Graph();

    public void addLink(Object originKey, Object targetKey, Object cond, Handler handler, boolean rollback) {
        Node originNode = getNode(originKey);
        Link link = originNode.linkTo(targetKey);
        link.setData(new LinkInfo(cond, handler, rollback));
    }

    public void setEntry(Object entryKey) {
        if (graph.containsNode(entryKey)) {
            this.entryKey = entryKey;
        }
        throw new IllegalArgumentException("key doesn't exists");
    }

    public synchronized final int process(CharSequence text, int start) throws IOException {
        StringProxy sp = new StringProxy(text, start);
        TextParser.State state = states[entryStateId];
        TextParser.Result reObj = new TextParser.Result();

        big_loop:
        while (true) {
            JavaTool.debug("Enter %s# state: (text = \"%s\")\n", state.id, sp);
            for (int index = 0; index < state.jumps.size(); index++) {
                TextParser.Jump jump = state.jumps.get(index);

                int result = jump.cond.judge(state.id, index, sp, reObj);

                if (result == FALSE_JUDGE) {
                    JavaTool.debug("  Condition %d: false\n", index);
                    continue;
                }

                if (result >= 0) {
                    if (JavaTool.isDebug()) {
                        StringBuilder builder = new StringBuilder();
                        builder.append(sp, 0, result);
                        JavaTool.debug("  Condition %d: successful (result = %d, text = %s)\n", index, result, builder);
                        builder.delete(0, builder.length());
                    }

                    if (jump.handler != null) {
                        jump.handler.hit(state.id, jump.targetId, index, reObj);
                    }

                    if (jump.targetId == EXIT_STATE_ID) {
                        JavaTool.debug("  exit the parser\n");
                        break big_loop;
                    }

                    if (!jump.rollback) {
                        if (result >= sp.length()) {
                            JavaTool.debug("### String is exhausted.\n");
                            break big_loop;
                        }
                        sp.setStart(sp.start + result);
                    }
                    state = states[jump.targetId];
                    JavaTool.debug("  move to %s# state\n", state.id);
                    continue big_loop;
                } else {
                    throw new RuntimeException("Illegal result");
                }
            }
            if (state.defaultTargetId == EXIT_STATE_ID) {
                JavaTool.debug("  No matched condition and exit the parser\n");
                break big_loop;
            } else {
                state = states[state.defaultTargetId];
                JavaTool.debug("  No matched condition and move to %s# state\n", state.id);
            }
        }
        return sp.start - start;
    }

    private Node getNode(Object key) {
        Node node = graph.getNode(key);
        if (node == null) {
            node = graph.addNode(key);
        }
        return node;
    }

    private static class LinkInfo {

        private final Object condition;
        private final Handler handler;
        private final boolean rollback;

        private LinkInfo(Object condition, Handler handler, boolean rollback) {
            this.condition = condition;
            this.handler = handler;
            this.rollback = rollback;
        }
    }

    public static interface Handler {
    }

    private static final class StringProxy implements CharSequence {

        private final CharSequence text;
        private int start;

        public StringProxy(CharSequence text, int start) {
            assert text != null;
            this.text = text;
            this.start = start;
        }

        public void setStart(int start) {
            this.start = start;
        }

        public int length() {
            return text.length() - start;
        }

        public char charAt(int index) {
            return text.charAt(start + index);
        }

        public CharSequence subSequence(int start, int end) {
            throw new UnsupportedOperationException("Not supported yet.");
        }

        public String toString() {
            StringBuilder sb = new StringBuilder();
            sb.append(text, start, text.length());
            return sb.toString();
        }
    }
}
*/